﻿using System.Xml.Linq;
using Microsoft.Practices.Unity;
using SharePointUtilitiesForDevelopers.Action;
using SharePointUtilitiesForDevelopers.Gateway;
using SharePointUtilitiesForDevelopers.ListsService;
using SharePointUtilitiesForDevelopers.Mapper;
using SharePointUtilitiesForDevelopers.Repository;
using SharePointUtilitiesForDevelopers.Service;
using SharePointUtilitiesForDevelopers.SiteDataService;
using SharePointUtilitiesForDevelopers.SitesService;
using SharePointUtilitiesForDevelopers.UserGroupService;
using SharePointUtilitiesForDevelopers.ViewsService;
using SharePointUtilitiesForDevelopers.WebsService;

namespace SharePointUtilitiesForDevelopers
{
    /// <summary>
    /// Locates instances at runtime.
    /// </summary>
    public static class ServiceLocator
    {
        #region Fields

        private static readonly IUnityContainer _container = new UnityContainer();

        #endregion Fields

        /// <summary>
        /// Initializes the <see cref="ServiceLocator"/> class.
        /// </summary>
        static ServiceLocator()
        {
            // Default mappings
            // Unit tests and clients can override this by registering types

            // Mapper
            RegisterType<IMapper<XElement, SharePointContentType>, SharePointContentTypeMapper>();
            RegisterType<IMapper<XElement, SharePointList>, SharePointListMapper>();
            RegisterType<IMapper<XElement, SharePointListItem>, SharePointListItemMapper>();
            RegisterType<IMapper<XElement, SharePointListView>, SharePointListViewMapper>();
            RegisterType<IMapper<XElement, SharePointWeb>, SharePointWebMapper>();
            RegisterType<IMapper<XElement, SharePointField>, SharePointFieldMapper>();

            // Service
            RegisterType<ISharePointServiceClientFactory<ListsSoapClient, ListsSoap>, SharePointListServiceClientFactory>();
            RegisterType<ISharePointServiceClientFactory<SitesSoapClient, SitesSoap>, SharePointSitesServiceClientFactory>();
            RegisterType<ISharePointServiceClientFactory<SiteDataSoapClient, SiteDataSoap>, SharePointSiteDataServiceClientFactory>();
            RegisterType<ISharePointServiceClientFactory<UserGroupSoapClient, UserGroupSoap>, SharePointUserGroupServiceClientFactory>();
            RegisterType<ISharePointServiceClientFactory<WebsSoapClient, WebsSoap>, SharePointWebsServiceClientFactory>();
            RegisterType<ISharePointServiceClientFactory<ViewsSoapClient, ViewsSoap>, SharePointViewsServiceClientFactory>();
     
            // Gateway
            RegisterType<ISharePointListsServiceGateway, SharePointListsServiceGateway>();
            RegisterType<ISharePointSiteDataServiceGateway, SharePointSiteDataServiceGateway>();
            RegisterType<ISharePointSitesServiceGateway, SharePointSitesServiceGateway>();
            RegisterType<ISharePointUserGroupServiceGateway, SharePointUserGroupServiceGateway>();
            RegisterType<ISharePointViewsServiceGateway, SharePointViewsServiceGateway>();
            RegisterType<ISharePointWebsServiceGateway, SharePointWebsServiceGateway>();

            // Repository
            RegisterType<ISharePointWebRepository, SharePointWebRepository>();
            RegisterType<ISharePointListRepository, SharePointListRepository>();

            // Action
            RegisterType<IActionManager, ActionManager>();
            RegisterType<IActionLoader, FileSystemActionLoader>();
        }

        #region Properties

        /// <summary>
        /// Gets the container.
        /// </summary>
        /// <value>The container.</value>
        public static IUnityContainer Container
        {
            get { return _container; }
        }

        #endregion Properties
        
        #region Static Methods

        /// <summary>
        /// Registers the type.
        /// </summary>
        /// <typeparam name="TFrom">The type of from.</typeparam>
        /// <typeparam name="TTo">The type of to.</typeparam>
        /// <param name="injectionMembers">The injection members.</param>
        public static void RegisterType<TFrom, TTo>(params InjectionMember[] injectionMembers) where TTo : TFrom
        {
            // register the type
            _container.RegisterType(typeof(TFrom), typeof(TTo), null, null, injectionMembers);
        }
        
        /// <summary>
        /// Registers the instance.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="instance">The instance.</param>
        public static void RegisterInstance<T>(T instance)
        {
            // register the instance
            _container.RegisterInstance(instance);
        }
        
        /// <summary>
        /// Resolves this instance.
        /// </summary>
        /// <typeparam name="T">The type to resolve.</typeparam>
        /// <returns>The registered instance of type <typeparamref name="T"/>.</returns>
        public static T Resolve<T>()
        {
            // resolve the instance
            return _container.Resolve<T>();
        }

        #endregion Static Methods
    }
}
